package com.winding.plugin.swagger;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import cn.hutool.core.io.FileUtil;
import cn.hutool.setting.dialect.Props;
import com.google.common.collect.Lists;
import com.winding.plugin.swagger.entity.SwaggerDoc;
import com.winding.plugin.swagger.utils.JsonUtils;
import io.swagger.models.Contact;
import io.swagger.models.Info;
import io.swagger.models.License;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.BufferedWriter;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLStreamHandler;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>swagger-doc maven 插件
 *
 * @author wind
 * @version 1.0
 * @goal generate
 * @phase package
 * @since 2018/12/10
 */
@Slf4j
public class SwaggerDocMojo extends AbstractMojo {

    /**
     * Location of the class files
     *
     * @parameter property="${project.build.directory}/lib"
     * @required
     */
    private String outputDirectory;

    /**
     * Location of the lib jars
     *
     * @parameter property="${project.build.directory}/lib"
     * @required
     */
    private String libDir;

    private URLClassLoader loader;
    @Override
    public void execute()
            throws MojoExecutionException, MojoFailureException {
        try {
            String libDir = (new URL("file", null, new File(this.libDir).getCanonicalPath() + File.separator)).toString();
            String baseDir = (new URL("file", null, new File(this.outputDirectory).getCanonicalPath() + File.separator)).toString();
            List<URL> libs = Lists.newArrayList();
            File libDirFile = new File(libDir.replaceAll("file:", ""));
            if (null != libDirFile.listFiles()) {
                for (File jar : libDirFile.listFiles()) {
                    libs.add(new URL(null, libDir + jar.getName(), (URLStreamHandler) null));
                }
            }
            libs.add(new URL(null, baseDir, (URLStreamHandler)null));
            log.info("libs.size:{}", libs.size());
            loader = new URLClassLoader(libs.toArray(new URL[libs.size()]));
            Path p = Paths.get(outputDirectory);
            log.info("directory:{}", p.toAbsolutePath());
            if (Files.notExists(p)) {
                Files.createDirectories(p);
            }
            p = p.resolve("swagger.properties");
            if (!Files.exists(p)) {
                log.info("缺少swagger.properties");
            } else {
                log.info("file:{}", p.toAbsolutePath());
                Properties props = Props.getProp(FileUtil.normalize(p.toFile().getAbsolutePath()));
                if (props.getProperty("basePackage") == null) {
                    log.info("缺少basePackage");
                    return;
                }
                SwaggerDoc swaggerDoc = initSwaggerDoc(props);
                log.info("swaggerDoc:{}", swaggerDoc);
                String data = JsonUtils.toJsonPretty(new SwaggerSourceParse(swaggerDoc, this.loader).parseJarSource());
                Path path = Paths.get(outputDirectory, "META-INF");
                if (Files.notExists(path)) {
                    Files.createDirectories(path);
                }
                path = path.resolve("swagger.json");
                BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8);
                writer.write(data);
                writer.flush();
                writer.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    private SwaggerDoc initSwaggerDoc(Properties props) {
        SwaggerDoc swaggerDoc = new SwaggerDoc();
        swaggerDoc.setUseWar(Boolean.valueOf(props.getProperty("useWar")));
        swaggerDoc.setSourceDir(props.getProperty("sourceDir"));
        swaggerDoc.setBasePackage(props.getProperty("basePackage"));
        swaggerDoc.setUseProjectFile(Boolean.valueOf(props.getProperty("useProjectFile")));
        Info info = new Info();
        License license = new License();
        Contact contact = new Contact();
        info.setContact(contact);
        info.setLicense(license);
        swaggerDoc.setInfo(info);
        swaggerDoc.setHost(props.getProperty("host"));
        swaggerDoc.setBasePath(props.getProperty("basePath"));
        swaggerDoc.setSwagger(props.getProperty("swagger"));
        String authHeaders=props.getOrDefault("authHeaders", "").toString();
        if(StringUtils.isNotBlank(authHeaders)){
            swaggerDoc.setAuthHeaders(Stream.of(authHeaders.split(",")).collect(Collectors.toList()));
        }


        String commonParams=props.getOrDefault("commonParams", "").toString();
        if(StringUtils.isNotBlank(commonParams)){
            swaggerDoc.setCommonParams(Stream.of(commonParams.split(",")).collect(Collectors.toList()));
        }
        info.setDescription(props.getProperty("info.description"));
        info.setTitle(props.getProperty("info.title"));
        info.setVersion(props.getProperty("info.version"));
        info.setTermsOfService(props.getProperty("info.termsOfService"));

        contact.setEmail(props.getProperty("info.contact.email"));
        contact.setName(props.getProperty("info.contact.name"));
        contact.setUrl(props.getProperty("info.contact.url"));

        license.setName(props.getProperty("info.license.name"));
        license.setUrl(props.getProperty("info.license.url"));
        return swaggerDoc;
    }
}
